package com.ruoyi.websokcet;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.domain.WebSocketMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * websocket服务端
 * 1. 监听新的websocket客户端连接及信息接收
 * 2. 广播发布消息至所有连接websocket客户端
 */
@Component
@ServerEndpoint("/websocket")
@Slf4j
public class WebSocketServer {
    //concurrent包的线程安全map，用来存放每个客户端对应的uuid 和 WebSocketServer对象。
    private static Map<String, WebSocketServer> websockets = new ConcurrentHashMap();

    //静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();

    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;

    //接收sid
    private String sid="";

    /**
     * 连接建立成功调用的方法
     * */
    @OnOpen
    public void onOpen(Session session, @PathParam("devicesno") String devidesno) {
        // 第一次连接生成一个uuid给前端
        final String uuid = UUID.randomUUID().toString();
        this.session = session;
        websockets.put(uuid, this);     //加入map中
        addOnlineCount();           //在线数加1
        log.error("有新窗口开始监听: 当前在线人数为" + getOnlineCount());

        // 返回 uuid 给前端
        WebSocketMessage<String> webSocketMessage = new WebSocketMessage<>("1", uuid, "首次连接返回uuid");
//        System.out.println("给前端的uuid: " + uuid);
        this.sendMessage(session, webSocketMessage);
    }

    /**
     * 连接关闭调用的方法
     * 需要把对应的websocket对象从map中删除
     */
    @OnClose
    public void onClose() {
        removeWebSocketServer(this); // 从 websockets map 中移出
        subOnlineCount();           //在线数减1
        log.info("有一连接关闭！当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("接收到的数据:  " + message);
        this.session = session;
//        log.info("收到来自窗口"+sid+"的信息:"+message);
        WebSocketMessage webSocketMessage = JSONObject.parseObject(message, WebSocketMessage.class);
        if(webSocketMessage.getMessageType().equals("7")) {
            WebSocketServer webSocketServer = websockets.get(webSocketMessage.getUuid());
            WebSocketMessage<String> returnHeart = new WebSocketMessage<>("7", webSocketMessage.getUuid(), "心跳返回");
            try {
                webSocketServer.sendMessage(JSONObject.toJSONString(returnHeart));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 发生错误
     *
     * @param session 会话
     * @param error   错误
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }

    /**
     * 实现服务器主动推送 自己不接收
     */
    public void sendMessage(String message, Session session) throws IOException {
        if (!this.session.equals(session)) {
            this.session.getBasicRemote().sendText(message);
        }
    }
    /**
     * 实现服务器主动推送 给自己发送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 给指定session发送消息
     * @param message
     * @throws IOException
     */
    public void sendMessage(Session session, WebSocketMessage message) {
        try {
            session.getBasicRemote().sendText(JSON.toJSONString(message));
        } catch (IOException e) {
            log.error("websocket 服务器发生错误~");
            e.printStackTrace();
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

    public static synchronized WebSocketServer getServer(String uuid) {
        return websockets.get(uuid);
    }

    /**
     * 去掉断开连接的客户端
     * @param server
     */
    public static synchronized void removeWebSocketServer(WebSocketServer server) {
        final Set<String> keySet = websockets.keySet();
        for (String key : keySet) {
            if (server.equals(websockets.get(key))) {
                websockets.remove(key);
                break;
            }
        }
    }
}
